package com.vcredit.creditcat.service.product;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.constraints.NotEmpty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.vcredit.bird.api.ICreditProductService;
import com.vcredit.bird.vo.product.CreditSubmitDto;
import com.vcredit.creditcat.bean.SpringContextHolder;
import com.vcredit.creditcat.dto.creditrepository.AuthItemDto;
import com.vcredit.creditcat.dto.product.ProductDecisionResultDto;
import com.vcredit.creditcat.dto.product.ProductExpireItem;
import com.vcredit.creditcat.dto.resource.ResourceDto;
import com.vcredit.creditcat.enumtype.AuthItemEnum;
import com.vcredit.creditcat.enumtype.BankCardTypeEnum;
import com.vcredit.creditcat.enumtype.MerchantProductEnum;
import com.vcredit.creditcat.exception.ProductCanNotApplyException;
import com.vcredit.creditcat.exception.ResourceException;
import com.vcredit.creditcat.manager.CustProductManager;
import com.vcredit.creditcat.manager.resource.FtpResourceManager;
import com.vcredit.creditcat.model.AuthAccumulation;
import com.vcredit.creditcat.model.AuthAlipay;
import com.vcredit.creditcat.model.AuthCreditcard;
import com.vcredit.creditcat.model.AuthIdentity;
import com.vcredit.creditcat.model.AuthItem;
import com.vcredit.creditcat.model.AuthJd;
import com.vcredit.creditcat.model.AuthMobile;
import com.vcredit.creditcat.model.AuthNetcredit;
import com.vcredit.creditcat.model.AuthPersonalInfo;
import com.vcredit.creditcat.model.AuthSchoolInfo;
import com.vcredit.creditcat.model.AuthSecredit;
import com.vcredit.creditcat.model.AuthSocial;
import com.vcredit.creditcat.model.AuthTaobao;
import com.vcredit.creditcat.model.CreditAssure;
import com.vcredit.creditcat.model.Cust;
import com.vcredit.creditcat.model.CustCard;
import com.vcredit.creditcat.model.CustProductApply;
import com.vcredit.creditcat.model.CustProductApplyRecord;
import com.vcredit.creditcat.model.ProductEnum;
import com.vcredit.creditcat.model.ProductItem;
import com.vcredit.creditcat.model.Relative;
import com.vcredit.creditcat.model.base.AbstractItem;
import com.vcredit.creditcat.service.AuthAccumulationService;
import com.vcredit.creditcat.service.AuthAlipayService;
import com.vcredit.creditcat.service.AuthCreditcardService;
import com.vcredit.creditcat.service.AuthIdentityService;
import com.vcredit.creditcat.service.AuthItemService;
import com.vcredit.creditcat.service.AuthJdService;
import com.vcredit.creditcat.service.AuthMobileService;
import com.vcredit.creditcat.service.AuthNetcreditService;
import com.vcredit.creditcat.service.AuthPersonalInfoService;
import com.vcredit.creditcat.service.AuthSchoolInfoService;
import com.vcredit.creditcat.service.AuthSecreditService;
import com.vcredit.creditcat.service.AuthSocialService;
import com.vcredit.creditcat.service.AuthTaobaoService;
import com.vcredit.creditcat.service.CreditAssureService;
import com.vcredit.creditcat.service.CustCardService;
import com.vcredit.creditcat.service.CustCreditRepositoryService;
import com.vcredit.creditcat.service.CustProductApplyRecordService;
import com.vcredit.creditcat.service.CustProductApplyService;
import com.vcredit.creditcat.service.CustService;
import com.vcredit.creditcat.service.ProductEnumService;
import com.vcredit.creditcat.service.ProductItemService;
import com.vcredit.creditcat.service.RelativeService;
import com.vcredit.creditcat.util.ConcurrentDateUtil;
import com.vcredit.creditcat.util.Utility;
import com.vcredit.framework.annotation.Log;
import com.vcredit.framework.util.BeanUtil;

@Service("productStrategyContext")
public class CreditCommonApplyService implements ICreditCommonService {
  private Logger logger = LoggerFactory.getLogger(CreditCommonApplyService.class);
  @Autowired
  private CustService custService;
  @Autowired
  private CustProductApplyService custProductApplyService;
  @Autowired
  private CustProductManager custProductManager;
  @Autowired
  private ProductItemService productItemService;
  @Autowired
  private CustProductApplyRecordService custProductApplyRecordService;
  @Autowired
  private AuthPersonalInfoService authPersonalInfoService;
  @Autowired
  private AuthIdentityService authIdentityService;
  @Autowired
  private AuthMobileService authMobileService;
  @Autowired
  private AuthSchoolInfoService authSchoolInfoService;
  @Autowired
  private AuthNetcreditService authNetcreditService;
  @Autowired
  private AuthAlipayService authAlipayService;
  @Autowired
  private CustCardService custCardService;
  @Autowired
  private AuthSocialService authSocialService;
  @Autowired
  private AuthAccumulationService authAccumulationService;
  @Autowired
  private AuthTaobaoService authTaobaoService;
  @Autowired
  private AuthJdService authJdservice;
  @Autowired
  private AuthSecreditService authSecreditService;
  @Autowired
  private AuthCreditcardService authCreditcardService;
  @Autowired
  private RelativeService relativeService;
  @Autowired
  private CreditAssureService creditAssureService;
  @Autowired
  private FtpResourceManager ftpResourceManager;
  @Autowired
  private ProductEnumService productEnumService;
  @Autowired
  private AuthItemService authItemService;
  @Autowired
  private CustCreditRepositoryService custCreditRepositoryService;

  // 使用策略封装信用项
  @Log
  @Override
  public Map<String, Object> getAuthMap(Cust cust, @NotEmpty Long processId, @NotEmpty int minCode)
      throws Exception {
    Long custId = cust.getCustId();
    Map<String, Object> result = new HashMap<String, Object>();
    Map<AuthItemEnum, Object> map = new EnumMap<AuthItemEnum, Object>(AuthItemEnum.class);
    List<ProductExpireItem> expiredList = new ArrayList<ProductExpireItem>();
    // 人个信息
    if ((minCode & AuthItemEnum.BASE_INFO.getCode()) == AuthItemEnum.BASE_INFO.getCode()) {
      AuthPersonalInfo personalInfo = authPersonalInfoService.findByProcessId(processId);
      map.put(AuthItemEnum.BASE_INFO, personalInfo);
    }
    // 身份证或人脸识别
    if ((minCode & AuthItemEnum.IDENTITY_REAL.getCode()) == AuthItemEnum.IDENTITY_REAL.getCode()||(minCode & AuthItemEnum.VERIFY_FACE_PAIR.getCode()) == AuthItemEnum.VERIFY_FACE_PAIR.getCode()) {
      if(map.get(AuthItemEnum.IDENTITY_REAL)==null){
        AuthIdentity identity = authIdentityService.findByProcessId(processId);
        if((minCode & AuthItemEnum.VERIFY_FACE_PAIR.getCode()) == AuthItemEnum.VERIFY_FACE_PAIR.getCode() && StringUtils.isNotBlank(identity.getIdFace())){
          identity.setIdHandheld(identity.getIdFace());
        }
        map.put(AuthItemEnum.IDENTITY_REAL, identity);
      }
    }
    // 绑卡认证
    if ((minCode & AuthItemEnum.DEBIT_CARD.getCode()) == AuthItemEnum.DEBIT_CARD.getCode()) {
      List<CustCard> findByCustIdAndCardTypeList =
          custCardService.findByCustIdAndCardType(custId, BankCardTypeEnum.DEBIT);
      if (findByCustIdAndCardTypeList.size() > 0) {
        map.put(AuthItemEnum.DEBIT_CARD, findByCustIdAndCardTypeList.get(0));
      }
    }
    // 手机认证
    if ((minCode & AuthItemEnum.MOBILE.getCode()) == AuthItemEnum.MOBILE.getCode()) {
      AuthMobile mobile = authMobileService.findByProcessIdAndType(processId,0);
      this.handleExpireItem(AuthItemEnum.MOBILE, cust, mobile, expiredList);
      map.put(AuthItemEnum.MOBILE, mobile);
    }
    // 学历认证
    if ((minCode & AuthItemEnum.EDUCATION.getCode()) == AuthItemEnum.EDUCATION.getCode()) {
      AuthSchoolInfo school = authSchoolInfoService.findByProccessId(processId);
      map.put(AuthItemEnum.EDUCATION, school);
    }
    // 央行征信
    if ((minCode & AuthItemEnum.BANK_CREDIT.getCode()) == AuthItemEnum.BANK_CREDIT.getCode()) {
      AuthNetcredit netCredit = authNetcreditService.findByProcessId(processId);
      this.handleExpireItem(AuthItemEnum.BANK_CREDIT, cust, netCredit, expiredList);
      map.put(AuthItemEnum.BANK_CREDIT, netCredit);
    }
    // 芝麻分
    if ((minCode & AuthItemEnum.SESAME_CREDIT.getCode()) == AuthItemEnum.SESAME_CREDIT.getCode()) {
      AuthSecredit secredit = authSecreditService.findByProcessId(processId);
      this.handleExpireItem(AuthItemEnum.SESAME_CREDIT, cust, secredit, expiredList);
      map.put(AuthItemEnum.SESAME_CREDIT, secredit);
    }
    // 社保
    if ((minCode & AuthItemEnum.SOCIAL_CREDIT.getCode()) == AuthItemEnum.SOCIAL_CREDIT.getCode()) {
      AuthSocial social = authSocialService.findByProcessId(processId);
      this.handleExpireItem(AuthItemEnum.SOCIAL_CREDIT, cust, social, expiredList);
      map.put(AuthItemEnum.SOCIAL_CREDIT, social);
    }
    // 公积金
    if ((minCode & AuthItemEnum.FUND_CREDIT.getCode()) == AuthItemEnum.FUND_CREDIT.getCode()) {
      AuthAccumulation accumulation = authAccumulationService.findByProccessId(processId);
      this.handleExpireItem(AuthItemEnum.FUND_CREDIT, cust, accumulation, expiredList);
      map.put(AuthItemEnum.FUND_CREDIT, accumulation);
    }
    // 支付宝
    if ((minCode & AuthItemEnum.ALIPAY.getCode()) == AuthItemEnum.ALIPAY.getCode()) {
      AuthAlipay alipay = authAlipayService.findByProcessId(processId);
      this.handleExpireItem(AuthItemEnum.ALIPAY, cust, alipay, expiredList);
      map.put(AuthItemEnum.ALIPAY, alipay);
    }
    // 淘宝
    if ((minCode & AuthItemEnum.TAOBAO.getCode()) == AuthItemEnum.TAOBAO.getCode()) {
      AuthTaobao taobao = authTaobaoService.findByProcessId(processId);
      this.handleExpireItem(AuthItemEnum.TAOBAO, cust, taobao, expiredList);
      map.put(AuthItemEnum.TAOBAO, taobao);
    }
    // 京东
    if ((minCode & AuthItemEnum.JINGDONG.getCode()) == AuthItemEnum.JINGDONG.getCode()) {
      AuthJd jd = authJdservice.findByProcessId(processId);
      this.handleExpireItem(AuthItemEnum.JINGDONG, cust, jd, expiredList);
      map.put(AuthItemEnum.JINGDONG, jd);
    }
    // 信用卡
    if ((minCode & AuthItemEnum.CREDIT_CARD.getCode()) == AuthItemEnum.CREDIT_CARD.getCode()) {
      AuthCreditcard creditcard = authCreditcardService.findByProcessId(processId);
      this.handleExpireItem(AuthItemEnum.CREDIT_CARD, cust, creditcard, expiredList);
      map.put(AuthItemEnum.CREDIT_CARD, creditcard);
    }
    // 紧急联系人
    if ((minCode & AuthItemEnum.CONTACTS.getCode()) == AuthItemEnum.CONTACTS.getCode()) {
      List<Relative> findByCustIdList = relativeService.findByCustId(custId);
      map.put(AuthItemEnum.CONTACTS, findByCustIdList);
    }
    //机构版征信 
    if ((minCode & AuthItemEnum.FOREIGN_CREDIT.getCode()) == AuthItemEnum.FOREIGN_CREDIT.getCode()) {
      CreditAssure creditAssure = creditAssureService.findByProcessId(processId);
      this.handleExpireItem(AuthItemEnum.FOREIGN_CREDIT, cust, creditAssure, expiredList);
      map.put(AuthItemEnum.FOREIGN_CREDIT, creditAssure);
    }
    if (expiredList.size() > 0) {
      result.put("expiredList", expiredList);
      return result;
    }
    result.put("authMap", map);
    return result;
  }

  private void handleExpireItem(AuthItemEnum authItemEnum, Cust cust, AbstractItem authItem,
      List<ProductExpireItem> expiredList) throws Exception {
    if (authItem.computeExpire()) {
      // 重置信用项状态和扣除用户对该认证项的完成分
      custCreditRepositoryService.getStatus(authItemEnum.getCode() + "", 1, cust);
      ProductExpireItem expiredItem = getExpireItemByCode(authItemEnum.getCode());
      expiredList.add(expiredItem);
    }
  }


  /**
  * @description: TODO(获取过期认证项)
  * @author: 张新功
   * @param code 
  * @return
  */

  private ProductExpireItem getExpireItemByCode(Integer code) {
    AuthItem item = authItemService.getItemByCode(code);
    ProductExpireItem expiredItem =
        new ProductExpireItem(item.getItemName(), item.getItemDesc(), item.getItemIcon(), "1",
            item.getItemId(), item.getAuthCode());
    return expiredItem;
  }

  /**
   * 获取信用项输入参数
   *
   * @author xiaojingjing
   * @param cust
   * @param productId
   * @param productType
   * @return
   * @throws JsonProcessingException
   * @throws ParseException
   * @throws ProductCanNotApplyException
   */
  @Log
  public CreditSubmitDto getCreditSubmitParam(Cust cust, Long productId, String productType)
      throws JsonProcessingException, ParseException, ProductCanNotApplyException {

    CreditSubmitDto submit = null;
    //        new CreditSubmitDto(cust.getCustId(), cust.getCustName(), cust.getCustIdno(),
    //            cust.getCustMobile(), personalInfo.getEducationValue(),
    //            personalInfo.getMarriageValue(), flowNo);
    return submit;
  }


  @Log
  @Override
  @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public void recordCustProductApply(CustProductApply custProductApply) {
    if (null == custProductApply) {
      logger.error("申请记录不能为null");
    }
    custProductApply.setUpdateTime(new Date());
    CustProductApplyRecord custProductApplyRecord = new CustProductApplyRecord();
    BeanUtil.copy(custProductApply, custProductApplyRecord);
    custProductApplyRecord.setApplyId(null);
    custProductApplyRecord.setCreateTime(new Date());
    custProductApplyRecord.setUpdateTime(new Date());
    custProductApplyRecordService.saveCustProductApplyRecord(custProductApplyRecord);
  }

  @Log
  @Override
  @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public void updateCustProductApplyByFlow(ProductDecisionResultDto paramDto)
      throws ProductCanNotApplyException {
    String flowNo = paramDto.getFlowNo();
    CustProductApply param = new CustProductApply();
    param.setFlowNo(flowNo);
    List<CustProductApply> findByConditions = custProductApplyService.findByConditions(param);
    if (Utility.isNullOrEmpty(findByConditions)) {
      throw new ProductCanNotApplyException(String.format("流水号%s不在在", flowNo));
    }
    CustProductApply custProductApply = findByConditions.get(0);
    CustProductApply objApply = new CustProductApply();
    BeanUtil.copy(paramDto, objApply);
    objApply.setApplyId(custProductApply.getApplyId());
    custProductApplyService.update(objApply);
    this.recordCustProductApply(objApply);
  }

  /**
   * 保存申请记录
   * @param custProductApply
   */
  @Log
  @Override
  @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public void saveCustProductApply(CustProductApply custProductApply) {
    Long applyId = custProductApply.getApplyId();
    if (null == applyId) {
      custProductApply.setCreateTime(new Date());
      custProductApply.setUpdateTime(new Date());
      custProductApplyService.insert(custProductApply);
      this.recordCustProductApply(custProductApply);
    } else {
      custProductApplyService.update(custProductApply);
      this.recordCustProductApply(custProductApply);
    }
  }

  /**
   * 验证申请人的申请状态是否正确
   *
   * @author xiaojingjing
   * @param productApply
   * @throws ProductCanNotApplyException
   * @throws ParseException
   */
  @Log
  @Override
  public void acceptable(CustProductApply productApply) throws ProductCanNotApplyException,
      ParseException {
    // 审核结果 0：已审批-失败；1：已审批-成功；2：审批中；3：未申请过；4：未申请过，认证条件齐全
    if (null == productApply) {
      return;
    }
    Integer auditStatus = productApply.getAuditResult();
    if (null == auditStatus) {
      throw new ProductCanNotApplyException("申请状态不能为空");
    }
    // 可以申请的状态包括： 4：未申请过，认证条件齐全；
    switch (auditStatus) {
      case 0:
        // 0：已审批-失败，可以再次申请且申请时间符合要求的
        String applyTime = productApply.getCreditApplyTime();
        if (!productApply.getIsApply() || StringUtils.isBlank(applyTime)
            || ConcurrentDateUtil.strToDate(applyTime).after(new Date())) {
          throw new ProductCanNotApplyException("已申批失败且不能再申请");
        }
        break;
      case 1:
        // 对于审批成功，但额度为空或额度小于等于0 的 允许再次申请
        if (productApply.getCreditAmt() > 0) {
          throw new ProductCanNotApplyException("已申批成功且额度已经申请成功");
        }
        break;
      case 2:
        throw new ProductCanNotApplyException("申请审批中，请勿重复申请");
      case 3:
        throw new ProductCanNotApplyException("认证条件不齐全");
      case 4:
        // 满足申请条件
        break;
      default:
        throw new ProductCanNotApplyException("条件不符");
    }
  }

  /** 
   * TODO 简单描述该方法的实现功能（可选）. 
   * @throws ParseException 
   * @see com.vcredit.creditcat.service.product.ICreditCommonService
   */
  @SuppressWarnings("unchecked")
  @Log
  @Override
  public Object prepareProductApplyUserInfo(Long custId, Long productId,
      MerchantProductEnum productEnum,Map<String,String> otherParams) throws ProductCanNotApplyException, ParseException,
      Exception {
    Cust cust = custService.findById(custId); // 查询登录用户
    CustProductApply findNewApplyProduct =
        custProductApplyService.findNewApplyProduct(productId, custId);
    this.acceptable(findNewApplyProduct);
    ProductItem productItem = productItemService.findByProductId(productId);
    //获取产品接口
    ICreditProductService productBirdService =
        (ICreditProductService) SpringContextHolder.getBean(productEnum.name().concat("Service"));//获取bird接口
    IProductApplyService productApplyService =
        (IProductApplyService) SpringContextHolder.getBean(productEnum.name());
    Long processId = cust.getLastProccessId();
    // 判断用户最小认证项是否认证完成
    List<AuthItemDto> unAuthList = custProductManager.queryProductItem(processId, productId, false);
    if (unAuthList != null && !unAuthList.isEmpty()) {
      throw new ProductCanNotApplyException("请完成认证后再尝试");
    }
    // 获取完成的认证项
    Map<String, Object> resultMap = this.getAuthMap(cust, processId, productItem.getMinCode());
    if (resultMap.containsKey("expiredList")) {
      //返回给前端 过期的信用项
      return resultMap;
    }

    Map<AuthItemEnum, Object> autMap = (Map<AuthItemEnum, Object>) resultMap.get("authMap");

    Object productCheckCreditParam = productApplyService.getProductCheckCreditParam(cust);
    Object checkOutput = productBirdService.checkCredit(productCheckCreditParam);
    Object checkCreditResult =
        productApplyService.checkCreditResult(custId, productId, checkOutput);
    if (null == checkCreditResult) {
      return null;
    }

    Object productCommitParam = productApplyService.getProductCommitParam(productId, cust, autMap,otherParams);
    Object commitOutput = productBirdService.commit(productCommitParam);
    return commitOutput;
  }

  /** 
   * TODO 简单描述该方法的实现功能（可选）. 
   * @throws Exception 
   * @throws ProductCanNotApplyException 
   * @see com.vcredit.creditcat.service.product.ICreditCommonService
   */
  @Log
  @Override
  public Object getAuditResult(Object outputDto, MerchantProductEnum productEnum)
      throws ProductCanNotApplyException, Exception {

    //获取产品接口
    ICreditProductService productBirdService =
        (ICreditProductService) SpringContextHolder.getBean(productEnum.name().concat("Service"));//获取bird接口
    Object queryLimit = productBirdService.getCredit(outputDto);
    return queryLimit;
  }


  @Log
  @Override
  public CustProductApply getCreditAmoutResult(CustProductApply custProductApply,
      MerchantProductEnum productEnum) throws ProductCanNotApplyException, Exception {
    Long custId = custProductApply.getCustId();
    Long productId = custProductApply.getProductId();
    Cust cust = custService.findById(custId);
    ProductItem productItem = productItemService.findByProductId(productId);
    //获取产口接口
    ICreditProductService productBirdService =
        (ICreditProductService) SpringContextHolder.getBean(productEnum.name().concat("Service"));//获取bird接口
    IProductApplyService productApplyService =
        (IProductApplyService) SpringContextHolder.getBean(productEnum.name());
    Object creditAmountParam = productApplyService.getCreditAmountParam(cust, productItem);
    if (null == creditAmountParam) {
      return null;
    }
    Object blackDto = productBirdService.getCredit(creditAmountParam);
    CustProductApply saveAuditResultParam =
        productApplyService.getSaveAuditResultParam(custId, productId, blackDto);
    return saveAuditResultParam;
  }

  @Log
  @Override
  public String getBase64StringByCode(String resourceCode) {
    ResourceDto downloadFaceResourceDto;
    String base64String = "";
    //转成base64
    try {
      downloadFaceResourceDto = ftpResourceManager.download(resourceCode);
      base64String = Base64.encodeBase64String(downloadFaceResourceDto.getResourceContent());
    } catch (ResourceException e) {
      e.printStackTrace();
    }
    return base64String;
  }

  @Log
  @Override
  public String getProductEnumCode(Long productId, Integer enumType, Integer catCode) {
    String productCode = "";
    List<ProductEnum> findAllList = productEnumService.findAllList();
    for (ProductEnum productEnum : findAllList) {
      Long productIdLocal = productEnum.getProductId();
      Integer enumTypeLocal = productEnum.getEnumType();
      Integer catCodeLoal = productEnum.getCatCode();
      if (productIdLocal == productId && enumTypeLocal == enumType && catCodeLoal == catCode) {
        productCode = productEnum.getProductCode();
      }
    }
    return productCode;
  }

}
